home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-20
/
pmpsrc11.zip
/
AX25DUMP.C
< prev
next >
Wrap
Text File
|
1991-07-30
|
9KB
|
426 lines
/*
AX25DUMP.C -- Dumps AX.25 packets in human readable format
Poor Man's Packet (PMP)
Copyright (c) 1991 by Andrew C. Payne All Rights Reserved.
Permission to use, copy, modify, and distribute this software and its
documentation without fee for NON-COMMERCIAL AMATEUR RADIO USE ONLY is hereby
granted, provided that the above copyright notice appear in all copies.
The author makes no representations about the suitability of this software
for any purpose. It is provided "as is" without express or implied warranty.
August, 1989
Andrew C. Payne
09/13/89 - changed to work with L2 packet structures /acp/
*/
/* ----- Includes ----- */
#include <stdio.h>
#include <conio.h>
#include <mem.h>
#include <alloc.h>
#include <string.h>
#include "pmp.h"
#ifdef NETROM
#include "netrom.h"
#endif
/* ----- Local Variables ----- */
static char ptext[1000]; /* packet text */
static char *ploc; /* current location in packet text */
/* cat(text)
Concatenates text string onto packet text string.
*/
static void cat(char *p)
{
while(*ploc++ = *p++)
;
ploc--;
}
/* ----- Level 1 to Level 2 conversion ----- */
/* AX25L1toL2(l1)
Given a pointer to a level 1 packet, converts it to a level 2 packet
structure and returns a pointer to the newly allocated level 2 packet
structure.
Returns NULL if an error in the structure of the level 1 packet
*/
struct ax25_packet *AX25L1toL2(struct ax25_level1 *p1)
{
struct ax25_packet p2;
struct ax25_packet *p;
byte *d;
byte t1,t2;
int cr[] = { UNKNOWN, RESPONSE, COMMAND, UNKNOWN };
if(p1->len < 17) /* no runt packets */
return NULL;
d = p1->data; /* packet data */
/* copy destination callsign and ssid */
memcpy(&p2.dest,d,MAXCLEN);
d += MAXCLEN;
p2.dest.ssid = SSIDMASK & (t1 = *d++);
/* copy source callsign and ssid */
memcpy(&p2.source,d,MAXCLEN);
d += MAXCLEN;
p2.source.ssid = SSIDMASK & (t2 = *d++);
/* command/response bits */
p2.cmdresp = cr[(((t1 & REPEATED) != 0) << 1) + ((t2 & REPEATED) != 0)];
/* copy digipeaters, if any */
p2.ndigis = 0;
while(p2.ndigis < MAXDIGIS && ((d[-1] & 1) == 0)) {
memcpy(&p2.digis[p2.ndigis],d,MAXCLEN);
d += MAXCLEN;
p2.digis[p2.ndigis].ssid = SSIDMASK & *d;
p2.repeated[p2.ndigis++] = REPEATED & *d++;
}
if(p2.ndigis == MAXDIGIS) /* too many digipeaters */
return NULL;
/* control field */
switch(FrameType(p2.cont = *d++)) {
case I:
case UI:
p2.pid = *d++; /* protocol ID */
}
/* allocate record and copy in header and data field, if any */
p2.dlen = p1->len - (d - p1->data) - 2; /* length remaining */
if(p2.dlen > 256 || p2.dlen < 0)
return NULL; /* out of range packets */
p = malloc(sizeof(struct ax25_packet) + p2.dlen);
if(p == NULL)
return NULL; /* out of memory */
memcpy(p, &p2, sizeof(struct ax25_packet));
if(p2.dlen)
memcpy(p->data, d, p2.dlen);
/* return pointer to allocated packet */
return p;
}
/* DumpLevel2Header(p)
Given a pointer to a Level 2 packet structure, creates a human readable
level 2 header and info field in ptext.
*/
void DumpLevel2Header(struct ax25_packet *p)
{
int i;
int showinfo; /* flag for fields w/ info */
int type; /* frame type */
char t[20]; /* temp space */
ploc = ptext;
/* print the to/from address */
cat(GetAX25Addr(&p->source));
cat(">");
cat(GetAX25Addr(&p->dest));
/* print digipeaters */
if(p->ndigis) {
cat(" [via ");
for(i=0; i<p->ndigis; i++) {
cat(GetAX25Addr(p->digis + i));
if(p->repeated[i])
cat("*");
if(i != (p->ndigis - 1))
cat(",");
}
cat("]");
}
/* decode and show control byte */
cat(" <");
showinfo = FALSE;
switch(type = FrameType(p->cont)) {
case I:
cat("I");
showinfo = TRUE;
break;
case RR:
cat("RR");
break;
case RNR:
cat("RNR");
break;
case REJ:
cat("REJ");
break;
case SABM:
cat("SABM");
break;
case DISC:
cat("DISC");
break;
case DM:
cat("DM");
break;
case UA:
cat("UA");
break;
case FRMR:
cat("FRMR");
break;
case UI:
cat("UI");
showinfo = TRUE;
break;
}
/* show the protocol ID */
if(showinfo) {
switch(p->pid) {
case PID_TEXT:
cat(" (Text)");
break;
case PID_NETROM:
cat(" (NET/ROM)");
break;
default:
sprintf(t," (PID=0x%X)",p->pid);
cat(t);
break;
}
}
/* show poll/final bit */
if(p->cont & PF) {
switch(p->cmdresp) {
case COMMAND:
cat(" (P)"); /* cmd, poll */
break;
case RESPONSE:
cat(" (F)"); /* resp, final */
break;
case UNKNOWN:
cat(" (P/F)");
break;
}
}
/* show sequence numbers */
if((type & 3) != U) {
sprintf(t," R%d",(p->cont >> 5) & 7);
cat(t);
}
if(type == I) {
sprintf(t," S%d",(p->cont >> 1) & 7);
cat(t);
}
cat(">");
}
#ifdef NETROM
/* ----- Net/Rom Packet Decoding ----- */
/* NRDumpBdcst(d)
Given a pointer to a broadcast data item, adds it to ptext.
*/
static void NRDumpBdcst(struct nr_broadcast *p)
{
char t[80],t1[10],t2[10];
/* copy space padded alias */
memcpy(t1,p->alias,6);
t1[6] = '\0';
/* show routing entry */
strcpy(t2, GetAX25Addr(&p->neighbor));
sprintf(t,"%10s %10s %10s %d\n",
GetAX25Addr(&p->dest),
t1,
t2,
p->quality);
cat(t);
}
/* NetRomDump(d,len)
Given a Net/Rom packet, dumps it in human readable form (adds it to
ptext)
*/
void NetRomDump(byte *d, int len)
{
char t[80],t1[10];
int i;
int data;
if(len == 0)
return;
data = FALSE;
cat(" NET/ROM: ");
/* handle routing broadcasts */
if(*d == 0xff) {
d++;
len--;
cat("Routing for ");
memcpy(t,d,6);
d += 6;
len -= 6;
t[6] = 0;
cat(t);
cat("\n");
for(i=0; i<11; i++) {
if(len == 0)
break;
NRDumpBdcst((struct nr_broadcast *)d);
d += sizeof(struct nr_broadcast);
len -= sizeof(struct nr_broadcast);
}
return;
}
/* decode network layer */
cat(GetAX25Addr(d));
cat(">");
cat(GetAX25Addr(d += sizeof(struct ax25_addr)));
d += sizeof(struct ax25_addr);
sprintf(t," (ttl=%u) ",*d++);
cat(t);
len -= (sizeof(struct ax25_addr) * 2 + 1);
/* decode transport layer */
switch(d[4] & 0x0f) {
case 0:
sprintf(t," Protocol %u, family %u",d[0],d[1]);
data = TRUE;
break;
case 1:
strcpy(t1, GetAX25Addr(d+6));
sprintf(t," Connect: %u/%u wnd %u %s@%s",
d[0],d[1],d[5],
t1,
GetAX25Addr(d+6+sizeof(struct ax25_addr)));
break;
case 2:
sprintf(t," Connect ack: ur %u/%u, my %u/%u, wnd %u",
d[0],d[1],d[2],d[3],d[5]);
break;
case 3:
sprintf(t," Disconnect: %u/%u",d[0],d[1]);
break;
case 4:
sprintf(t," Disconnect ack: %u/%u",d[0],d[1]);
break;
case 5:
sprintf(t," Info: %u/%u txseq %u rxseq %u ::",
d[0],d[1],d[2],d[3]);
data = TRUE;
break;
case 6:
sprintf(t," Info ack: %u/%u txseq %u rxseq %u",
d[0],d[1],d[2],d[3]);
break;
default:
sprintf(t," Unknown transport %u",d[4] & 0xf);
break;
}
cat(t);
/* copy in the data field, if any */
if(data) {
d += 5;
len -= 5;
cat("\n");
eol_in(EOL_CR, d, len);
while(len--) { /* quick hack */
if(*d)
*ploc++ = *d;
d++;
}
}
cat("\n");
}
#endif /* Net/Rom */
/* ----- Packet Dump Routines ----- */
/* ShowLevel2(p)
Given a pointer to a level 2 packet, shows the packet on the screen.
Munges packet data slightly (converts EOL).
*/
void ShowLevel2(struct ax25_packet *p)
{
/* show the header */
DumpLevel2Header(p);
if(p->dlen)
cat(":\n");
else
cat("\n");
GotoLeft();
uputs(BrightAttr,ptext);
/* show the data field if any */
if(p->dlen) {
switch(p->pid) {
#ifdef NETROM
case PID_NETROM:
ploc = ptext;
NetRomDump(p->data,p->dlen);
uputs(NormalAttr,ptext);
break;
#endif
default:
eol_in(EOL_CR, p->data, p->dlen);
uputtext(NormalAttr,p->data,p->dlen);
break;
}
}
/* make sure cursor is at column one */
GotoLeft();
}
/* DumpLevel2(p)
Given a pointer to a level 2 packet, translates the packet into
human readable form and returns a pointer to the text string.
(intended for file dump/log routines)
*/
char *DumpLevel2(struct ax25_packet *p)
{
byte *data;
int len;
/* decode header */
DumpLevel2Header(p);
if(p->dlen)
cat(":");
/* decode info field if any */
if(p->dlen) {
cat("\n");
switch(p->pid) {
case PID_TEXT: /* copy in data, crude */
len = p->dlen;
data = p->data;
while(len--)
*ploc++ = *data++;
break;
#ifdef NETROM
case PID_NETROM:
NetRomDump(p->data,p->dlen);
break;
#endif
}
}
*ploc = '\0'; /* terminate */
return ptext;
}